#ifndef HTTP_PROTOCOL_MSG_H_
#define HTTP_PROTOCOL_MSG_H_

#include <cstdint>
#include <map>
#include <string>
#include <vector>

class HttpUtil
{
public:
    // common header
    struct ContentEncoding
    {
        // Content-Encoding: gzip
        std::string m_encode_way;
    };
    struct ContentMd5
    {
        // Content-MD5: base64(md5-128)
        std::string m_base64_content;
    };
    // request header
    struct AcceptLanguage
    {
        // Accept-Language: da
        // Accept-Language: en-gb
        // Accept-Language: da, en-gb;q=0.9, en;q=0.7
        std::string m_language_range;
        double      m_qual_value;
    };
    struct ContentType
    {
        // Content-Type: text/html
        // Content-Type: text/html; charset=utf-8
        // Content-Type: application/json; charset=utf-8
        std::string m_main_type;
        std::string m_sub_type;
        std::string m_charset_way;
    };
    struct Range
    {
    };
    // response header
    struct AcceptRanges
    {
        // Accept-Ranges: bytes | none
        std::string m_value;
    };
    struct Age
    {
        // Age: 10
        int32_t m_delta_second;
    };
    struct ContentLanguage
    {
        // Content-Language: da
        // Content-Language: mi,en
        std::string m_lang;
    };
    struct ContentRange
    {
        // Content-Range: bytes-unit (first-byte-pos"-"last-byte-pos)/(instance-langth | *)
        // Content-Range: bytes 0-499/1234
        // Content-Range: bytes 500-999/1234
        // Content-Range: bytes 1000-1234/1234
        std::string m_byte_unit;
        int         m_first_pos;
        int         m_last_pos;
        int         m_instance_length;
    };
    struct Allow
    {
        std::vector<std::string> m_allow_method;
    };

public:
    // request
    static ContentType ParseContentType(const std::string & content);
    static std::string ComposeContentType(ContentType & content);

public:
    // response
    static std::vector<struct AcceptLanguage> ParseAcceptLanguage(const std::string & value);
    static std::string                        ComposeAcceptLanguage(std::vector<AcceptLanguage> & attr);
    static Age                                ParseAge(const std::string & age);
    static std::string                        ComposeAge(Age & age);
    static ContentRange                       ParseContentRange(const std::string & value);
    static std::string                        ComposeContentRange(ContentRange & range);
    static Allow                              ParseAllow(const std::string & allow);
    static std::string                        ComposeAllow(Allow & allow);

public:
    // common
public:
    static std::string CodeReasonPhrases(int code);
    static std::string ToLower(const std::string & content);
};

class HttpRequest
{
public:
    HttpRequest();
    void                   AddHeaderLine(const std::string & method, const std::string & uri, const std::string & version);
    void                   AddHeaderSign(const std::string & header, const std::string & value);
    void                   AddHeaderBody(const uint8_t * data, int length);
    void                   Clear();
    std::string            GetMethod();
    std::string            GetUri();
    std::string            GetVersion();
    std::string            GetHeaderValue(const std::string & key);
    int                    GetContentLength();
    std::vector<uint8_t> & Body();
    void                   String(std::string & content);

private:
    std::string m_method;
    std::string m_uri;
    std::string m_version;

private:
    std::multimap<std::string, std::string> m_header_sign_map;
    std::vector<uint8_t>                    m_body_vec;
};

class HttpResponse
{
public:
    HttpResponse();
    std::string            GetCode();
    std::string            GetVersion();
    std::string            GetNote();
    std::vector<uint8_t> & Body();
    std::string            GetHeaderValue(const std::string & key);
    void                   Clear();
    void                   AddHeaderLine(const std::string & version, const std::string & code, const std::string & note);
    void                   AddHeaderSign(const std::string & key, const std::string & value);
    void                   String(std::string & content);

private:
    std::string m_version;
    std::string m_code;
    std::string m_note;

private:
    std::multimap<std::string, std::string> m_header_sign_map;
    std::vector<uint8_t>                    m_body_vec;
};

#endif //
